package com.zlx.mall.biz.order.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.zlx.mall.base.entity.*;
import com.zlx.mall.base.service.*;
import com.zlx.mall.basic.common.enums.NotDeteteEnum;
import com.zlx.mall.basic.common.exception.IllegalBizStatusException;
import com.zlx.mall.basic.datasource.enums.StatusEnum;
import com.zlx.mall.basic.mask.DataMaskHandler;
import com.zlx.mall.basic.util.DataNoGenerator;
import com.zlx.mall.basic.util.GuidUtil;
import com.zlx.mall.basic.web.model.BaseRequest;
import com.zlx.mall.basic.web.model.BaseResponse;
import com.zlx.mall.biz.goods.enums.GoodsTypeEnum;
import com.zlx.mall.biz.order.enums.OrderStatusEnum;
import com.zlx.mall.biz.order.model.CheckOrderRequest;
import com.zlx.mall.biz.order.model.CreateOrderRequest;
import com.zlx.mall.biz.order.model.OrderListResponse;
import com.zlx.mall.biz.order.model.ReceiveUpdateRequest;
import com.zlx.mall.biz.order.service.IOrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Author xiatian
 * @Date 2025/3/23 星期日 19:45
 * @注释
 */
@Slf4j
@Service
public class OrderServiceImpl implements IOrderService {
    @Autowired
    private IScComboCategoryService scComboCategoryService;
    @Autowired
    private IScUserService scUserService;
    @Autowired
    private IScComboService scComboService;
    @Autowired
    private IScTrolleyService scTrolleyService;
    @Autowired
    private IScCategoryService scCategoryService;
    @Autowired
    private IScGoodsOrderService scGoodsOrderService;
    @Autowired
    private IScGoodsService scGoodsService;
    @Autowired
    private IScGoodsOrderGoodsService scGoodsOrderGoodsService;
    @Autowired
    GuidUtil guidUtil;
    @Autowired
    private IScGoodsOrderReceiveInfoService scGoodsOrderReceiveInfoService;
    @Autowired
    private DataMaskHandler dataMaskHandler;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResponse create(BaseRequest request) {
        Long userId = request.getUserId();
        List<ScGoodsOrder> orders = scGoodsOrderService.list(new QueryWrapper<ScGoodsOrder>().eq(ScGoodsOrder.IS_DELETE, NotDeteteEnum.NOT_DELETE.getCode()).eq(ScGoodsOrder.USER_ID, userId).ne(ScGoodsOrder.STATUS, OrderStatusEnum.CANCEL.getCode()));
        if(CollUtil.isNotEmpty(orders)) throw new IllegalBizStatusException("您已提交过订单，请前去我的订单查看");
        CreateOrderRequest validate = request.toObjectAndValidate(CreateOrderRequest.class);
        List<ScTrolley> trolleys = scTrolleyService.listByIds(validate.getIds());
        log.info("用户={}的创建订单信息={}", userId, trolleys);
        if(null == userId || trolleys.isEmpty()) return BaseResponse.success();

        ScGoodsOrder order = new ScGoodsOrder();
        order.setUserId(userId);
        order.setStatus(OrderStatusEnum.INIT.getCode());
        String orderNo = guidUtil.createUid(DataNoGenerator.SHOP_MALL_ORDER, DataNoGenerator.PLATFORM, DataNoGenerator.SMO_INCR_KEY);
        order.setOrderNo(orderNo);
        order.setDeliveryMethod(validate.getDeliveryMethod());
        scGoodsOrderService.save(order);

        ScGoodsOrderReceiveInfo receiveInfo = new ScGoodsOrderReceiveInfo();
        receiveInfo.setConsignee(validate.getConsignee());
        receiveInfo.setConsigneeMobileEncrypt(dataMaskHandler.encrypt(validate.getConsigneeMobile()));
        receiveInfo.setConsigneeMobileMask(dataMaskHandler.maskMobile(validate.getConsigneeMobile()));
        receiveInfo.setConsigneeMobileMd5(dataMaskHandler.md5(validate.getConsigneeMobile()));
        receiveInfo.setAddress(validate.getAddress());
        receiveInfo.setDetailAddress(validate.getDetailAddress());
        receiveInfo.setOrderNo(orderNo);
        scGoodsOrderReceiveInfoService.save(receiveInfo);

        List<Long> goodsIds = removeNoComboGoods(trolleys, userId);
        List<ScGoods> scGoods = scGoodsService.list(new QueryWrapper<ScGoods>().in(ScGoods.ID, goodsIds).eq(ScGoods.STATUS, StatusEnum.ENABLE.getIntegerValue()).eq(ScGoods.IS_DELETE, NotDeteteEnum.NOT_DELETE.getCode()));
        Map<Long, ScGoods> goodsListMap = scGoods.stream().collect(Collectors.toMap(ScGoods::getId, Function.identity()));
        List<Long> subCategoryIds = scGoods.stream().map(ScGoods::getSubCategoryId).collect(Collectors.toList());
        Map<Long, ScCategory> scCategoryMap = scCategoryService.list(new QueryWrapper<ScCategory>().in(ScCategory.ID, subCategoryIds).eq(ScCategory.IS_DELETE, NotDeteteEnum.NOT_DELETE.getCode()))
                .stream().collect(Collectors.toMap(ScCategory::getId, Function.identity()));

        List<ScGoodsOrderGoods> goodsOrderGoods = new ArrayList<>();
        Map<Long, ScTrolley> goodsMap = trolleys.stream().collect(Collectors.toMap(ScTrolley::getGoodsId, Function.identity()));
        for (Map.Entry<Long, ScTrolley> entry : goodsMap.entrySet()) {
            Long goodsId = entry.getKey();
            ScGoods goods = goodsListMap.get(goodsId);
            ScTrolley scTrolley = entry.getValue();
            ScGoodsOrderGoods scGoodsOrderGoods = new ScGoodsOrderGoods();
            scGoodsOrderGoods.setOrderNo(order.getOrderNo());
            scGoodsOrderGoods.setGoodsId(scTrolley.getGoodsId());
            scGoodsOrderGoods.setGoodName(goods.getName());
            scGoodsOrderGoods.setSalePrice(goods.getSalePrice());
            if (Objects.equals(scTrolley.getType(), GoodsTypeEnum.UPGRADE.getCode())){
                BigDecimal sourceGoodsPrice = scGoodsService.getById(scTrolley.getSourceGoodsId()).getSalePrice();
                scGoodsOrderGoods.setSalePrice(goods.getSalePrice().subtract(sourceGoodsPrice));
            }else if(Objects.equals(scTrolley.getType(), GoodsTypeEnum.COMBO.getCode())) {
                scGoodsOrderGoods.setSalePrice(BigDecimal.ZERO);
            } else{
                scGoodsOrderGoods.setSalePrice(goods.getSalePrice());
            }
            scGoodsOrderGoods.setMainImg(goods.getMainImg());
            scGoodsOrderGoods.setCategoryId(scTrolley.getCategoryId());
            scGoodsOrderGoods.setSubCategoryId(goods.getSubCategoryId());
            scGoodsOrderGoods.setSubCategoryName(scCategoryMap.get(goods.getSubCategoryId()).getName());
            scGoodsOrderGoods.setNumber(scTrolley.getNumber());
            scGoodsOrderGoods.setType(scTrolley.getType());
            goodsOrderGoods.add(scGoodsOrderGoods);
        }
        scGoodsOrderGoodsService.saveBatch(goodsOrderGoods);
        scTrolleyService.remove(new QueryWrapper<ScTrolley>().eq(ScTrolley.USER_ID, userId));

        return BaseResponse.success();
    }

    private List<Long> removeNoComboGoods(List<ScTrolley> trolleys, Long userId) {
        List<Long> goodsIds = trolleys.stream().map(ScTrolley::getGoodsId).collect(Collectors.toList());
        log.info("购物车里的商品id={}", goodsIds);
        ScUser user = Optional.ofNullable(scUserService.getById(userId)).orElseThrow(() -> new IllegalBizStatusException("用户不存在"));
        ScCombo combo = scComboService.getOne(new QueryWrapper<ScCombo>().eq(ScCombo.SELECT_CODE, user.getSelectCode()).eq(ScCombo.IS_DELETE, NotDeteteEnum.NOT_DELETE.getCode()));
        List<ScComboCategory> comboCategories = scComboCategoryService.list(new QueryWrapper<ScComboCategory>().eq(ScComboCategory.COMBO_ID, combo.getId()).eq(ScComboCategory.IS_DELETE, NotDeteteEnum.NOT_DELETE.getCode()));
        List<Long> comboGoodsIds = comboCategories.stream().map(ScComboCategory::getGoodsId).collect(Collectors.toList());
        log.info("套餐里的商品id={}", comboGoodsIds);
        goodsIds.retainAll(comboGoodsIds);
        log.info("保留两个共有的goodsId={}", goodsIds);
        return goodsIds;
    }

    @Override
    public BaseResponse check(BaseRequest request) {
        Long userId =  request.getUserId();
        List<ScGoodsOrder> orders = scGoodsOrderService.list(new QueryWrapper<ScGoodsOrder>().eq(ScGoodsOrder.IS_DELETE, NotDeteteEnum.NOT_DELETE.getCode()).eq(ScGoodsOrder.USER_ID, userId).ne(ScGoodsOrder.STATUS, OrderStatusEnum.CANCEL.getCode()));
        if(CollUtil.isNotEmpty(orders)) throw new IllegalBizStatusException("您已提交过订单，请前去我的订单查看");
        ScUser user = Optional.ofNullable(scUserService.getById(userId)).orElseThrow(() -> new IllegalBizStatusException("用户不存在"));
        ScCombo combo = scComboService.getOne(new QueryWrapper<ScCombo>().eq(ScCombo.IS_DELETE, NotDeteteEnum.NOT_DELETE.getCode())
                .eq(ScCombo.SELECT_CODE, user.getSelectCode()).eq(ScCombo.STATUS, 1));
        if (null == combo) return BaseResponse.success();
        List<ScComboCategory> comboList = scComboCategoryService.list(new QueryWrapper<ScComboCategory>()
                .eq(ScComboCategory.COMBO_ID, combo.getId()).eq(ScComboCategory.IS_DELETE, NotDeteteEnum.NOT_DELETE.getCode()));
        List<Long> comboSubcategoryIds = comboList.stream().map(ScComboCategory::getSubCategoryId).collect(Collectors.toList());
        log.info("用户={}的套餐二级类目ID={}",userId, comboSubcategoryIds);
        CheckOrderRequest validate = request.toObjectAndValidate(CheckOrderRequest.class);
        List<Long> selectSubcategoryIds = validate.getCategoryIdList();
        List<Long> missingGoodsIds = comboSubcategoryIds.stream()
                .filter(id -> !selectSubcategoryIds.contains(id))
                .collect(Collectors.toList());
        log.info("套餐里包含的商品没有选中的={}",missingGoodsIds);
        if (CollUtil.isEmpty(missingGoodsIds)) return BaseResponse.success();

        String names = CollUtil.join(scCategoryService.listByIds(missingGoodsIds), ",", ScCategory::getName);
        throw new IllegalBizStatusException("没有选择套餐内包含的商品: "+names+"，请前去选择");
    }

    @Override
    public BaseResponse list(BaseRequest request) {
        Long userId = request.getUserId();
        List<ScGoodsOrder> orders = scGoodsOrderService.list(new QueryWrapper<ScGoodsOrder>().eq(ScGoodsOrder.USER_ID, userId).eq(ScGoodsOrder.IS_DELETE, NotDeteteEnum.NOT_DELETE.getCode())
                .orderByDesc(ScGoodsOrder.ID));
        if (CollUtil.isEmpty(orders)) return BaseResponse.success();

        Map<String, ScGoodsOrder> orderMap = orders.stream().collect(Collectors.toMap(ScGoodsOrder::getOrderNo, Function.identity()));
        Set<String> orderNos = orderMap.keySet();
        Map<String, List<ScGoodsOrderGoods>> goodsMap = scGoodsOrderGoodsService.list(new QueryWrapper<ScGoodsOrderGoods>().in(ScGoodsOrderGoods.ORDER_NO, orderNos))
                .stream().collect(Collectors.groupingBy(ScGoodsOrderGoods::getOrderNo));
        Map<String, ScGoodsOrderReceiveInfo> receiveInfoMap = scGoodsOrderReceiveInfoService.list(new QueryWrapper<ScGoodsOrderReceiveInfo>().in(ScGoodsOrderReceiveInfo.ORDER_NO, orderNos))
                .stream().collect(Collectors.toMap(ScGoodsOrderReceiveInfo::getOrderNo, Function.identity()));

        List<OrderListResponse> responses = new ArrayList<>();
        for (ScGoodsOrder order : orders) {
            OrderListResponse response = new OrderListResponse();
            response.setId(order.getId());
            response.setOrderNo(order.getOrderNo());
            response.setCreateTime(order.getCreateTimestamp());
            response.setStatus(OrderStatusEnum.getStatusDescByCode(order.getStatus()));
            response.setCompeteTime(order.getCompeteTime());
            ScGoodsOrderReceiveInfo receiveInfo = receiveInfoMap.get(order.getOrderNo());
            if (receiveInfo != null) {
                response.setAddress(receiveInfo.getAddress());
                response.setDetailAddress(receiveInfo.getDetailAddress());
                response.setConsignee(receiveInfo.getConsignee());
                response.setConsigneeMobile(dataMaskHandler.decrypt(receiveInfo.getConsigneeMobileEncrypt()));
            }

            List<OrderListResponse.GoodsList> goodsLists = new ArrayList<>();
            List<ScGoodsOrderGoods> goodsList = goodsMap.get(order.getOrderNo());
            for (ScGoodsOrderGoods goods : goodsList) {
                OrderListResponse.GoodsList goodsList1 = new OrderListResponse.GoodsList();

                goodsList1.setGoodsName(goods.getGoodName());
                goodsList1.setGoodsId(goods.getGoodsId());
                goodsList1.setSalePrice(goods.getSalePrice());
                goodsList1.setNumber(goods.getNumber());
                goodsList1.setType(goods.getType());
                goodsList1.setMainImg(goods.getMainImg());
                goodsList1.setSubCategoryName(goods.getSubCategoryName());
                goodsLists.add(goodsList1);
            }
            response.setGoodsList(goodsLists);
            responses.add(response);
        }

        return BaseResponse.success(responses);
    }

    @Override
    public BaseResponse receiveUpdate(BaseRequest request) {
        ReceiveUpdateRequest validate = request.toObjectAndValidate(ReceiveUpdateRequest.class);
        boolean update = scGoodsOrderReceiveInfoService.update(new UpdateWrapper<ScGoodsOrderReceiveInfo>()
                .set(ScGoodsOrderReceiveInfo.ADDRESS, validate.getAddress())
                .set(ScGoodsOrderReceiveInfo.DETAIL_ADDRESS, validate.getDetailAddress())
                .set(ScGoodsOrderReceiveInfo.CONSIGNEE, validate.getConsignee())
                .set(ScGoodsOrderReceiveInfo.CONSIGNEE_MOBILE_ENCRYPT, dataMaskHandler.encrypt(validate.getConsigneeMobile()))
                .set(ScGoodsOrderReceiveInfo.CONSIGNEE_MOBILE_MD5, dataMaskHandler.md5(validate.getConsigneeMobile()))
                .set(ScGoodsOrderReceiveInfo.CONSIGNEE_MOBILE_MASK, dataMaskHandler.maskMobile(validate.getConsigneeMobile()))
                .eq(ScGoodsOrderReceiveInfo.ORDER_NO, validate.getOrderNo())
                .eq(ScGoodsOrderReceiveInfo.IS_DELETE, NotDeteteEnum.NOT_DELETE.getCode()));
        return BaseResponse.success(update);
    }
}
